/*********************************************************************************************************************
 * COPYRIGHT NOTICE
 * Copyright (c) 2018,逐飞科技
 * All rights reserved.
 * 技术讨论QQ群：	一群：179029047(已满)
 *					二群：244861897(已满)
 *					三群：824575535
 *
 * 以下所有内容版权均属逐飞科技所有，未经允许不得用于商业用途，
 * 欢迎各位使用并传播本程序，修改内容时必须保留逐飞科技的版权声明。
 *
 * @file			zf_usart.c
 * @company			成都逐飞科技有限公司
 * @author			逐飞科技(QQ3184284598)
 * @version			查看doc内version文件 版本说明
 * @Software		IAR 8.3 or MDK 5.24
 * @Taobao			https://seekfree.taobao.com/
 * @date			2020-03-25
 * @note			本文件作为 LPC55S 系列芯片开源库外设文件
					提供 USART 外设驱动
 ********************************************************************************************************************/
#include "zf_usart.h"
#include "zf_isr.h"

usart_handle_t g_uartHandle[8];																	// FC 的 USART 中断句柄

//-------------------------------------------------------------------------------------------------------------------
//	@brief		获取 USART 默认设置
//	@param		config			FC所选功能的配置参数结构体
//	Sample usage:				zf_usart_get_default_config(config);
//-------------------------------------------------------------------------------------------------------------------
void zf_usart_get_default_config (usart_config_t *config)
{
	assert(config != NULL);																		// 确认参数正确
	USART_GetDefaultConfig(config);																// 获取默认设置
	config->enableTx		= true;																// 开启 TX 发送
	config->enableRx		= true;																// 开启 RX 接收
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		修改 USART 设置
//	@param		config			FC所选功能的配置参数结构体
//	@param		param_index		对应参数的索引
//	@param		data			参数数值
//	Sample usage:				zf_usart_param_set( config, USART_PARAM_BAUD_RATE, USART_PARAM_BAUD_RATE_115200 );	
//-------------------------------------------------------------------------------------------------------------------
void zf_usart_param_set  (usart_config_t *config, usart_param_t param_index, uint32_t data)
{
	switch(param_index)
	{
		case USART_PARAM_BAUD_RATE :															// 波特率参数
			config->baudRate_Bps = data;														// 更新波特率
			break;
		case USART_PARAM_PARITY_MODE :															// 校验模式
			config->parityMode = (usart_parity_mode_t) data;									// 更新校验模式
			break;
		case USART_PARAM_STOP_BITS :															// 停止位
			config->stopBitCount = (usart_stop_bit_count_t) data;								// 更新停止位
			break;
		case USART_PARAM_DATA_BITS :															// 数据位长度
			config->bitCountPerChar = (usart_data_len_t) data;									// 更新数据位长度
			break;
		case USART_PARAM_LOOP_BACK :															// 芯片内部 USART 回环
			config->loopback = (bool) data;														// 更新使能状态
			break;
		case USART_PARAM_RX_FUNC :																// 接收 RX 功能
			config->enableRx = (bool) data;														// 更新 RX 使能
			break;
		case USART_PARAM_TX_FUNC :																// 发送 TX 功能
			config->enableTx = (bool) data;														// 更新 TX 使能
			break;
		case USART_PARAM_CONTINUOUS_CLOCK :														// 同步模式时钟输出模式
			config->enableContinuousSCLK = (bool) data;											// 更行同步模式时钟模式
			break;
		case USART_PARAM_TX_FIFO :																// 发送 TX 触发条例
			config->txWatermark = (usart_txfifo_watermark_t) data;								// 修改发送 TX 触发条例数目
			break;
		case USART_PARAM_RX_FIFO :																// 接收 RX 触发条例
			config->rxWatermark = (usart_rxfifo_watermark_t) data;								// 修改接收 RX 触发条例数目
			break;
		case USART_PARAM_SYNC_MODE :															// USART 同步模式
			config->syncMode = (usart_sync_mode_t) data;										// 更改同步模式
			break;
		case USART_PARAM_CLOCK_POLARITY :														// 同步模式时钟属性
			config->clockPolarity = (usart_clock_polarity_t) data;								// 修改同步模式时钟属性
			break;
		default:
			break;
	}
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		建立 USART Transfer
//	@param		index			所选 USART 标识
//	@param		callback		指定的 transfer 回调函数 ( 中断方式传输回调 )
//	Sample usage:				zf_usart_transfer_great_handle( USART_INDEX0, USART_UserCallback );
//-------------------------------------------------------------------------------------------------------------------
void zf_usart_transfer_great_handle (flexcomm_index_list index, usart_transfer_callback_t callback)
{
	assert(index <= 7);																			// 确认参数正确
	USART_TransferCreateHandle
	(
		usart_index[index],																		// 对应 USART
		&g_uartHandle[index],																	// 对应处理结构体
		callback,																				// 用户定义中断处理函数
		NULL																					// 屏蔽用户中断处理函数参数
	);
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		打开对应 USART 端口中断使能
//	@param		index			所选 USART 标识
//	@param		handler(void)	指定的自拟定中断服务函数
//	Sample usage:				zf_usart_interrupt_enable( USART_INDEX0, USART_INTERRUPT_MODE_RXLVL, USART0_IRQHandler );
//-------------------------------------------------------------------------------------------------------------------
void zf_usart_interrupt_enable (flexcomm_index_list index, void handler(void))
{
	assert(index <= 7 && handler != NULL);
	flexcomm_irqn_func[index] = handler;
	EnableIRQ(flexcomm_irqn[index]);
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		关闭对应 USART 端口中断使能
//	@param		index			所选 USART 标识
//	Sample usage:				zf_usart_interrupt_disable( USART_INDEX0 );
//-------------------------------------------------------------------------------------------------------------------
void zf_usart_interrupt_disable (flexcomm_index_list index)
{
	assert(index <= 7);
	DisableIRQ(flexcomm_irqn[index]);
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		修改对应 USART 端口中断方式
//	@param		index			所选 USART 标识
//	@param		interrput_mode	所选中断方式
//	Sample usage:				zf_usart_interrupt_mode_set( USART_INDEX0, USART_INTERRUPT_MODE_TXLVL );
//-------------------------------------------------------------------------------------------------------------------
void zf_usart_interrupt_mode_set (flexcomm_index_list index, uint8_t interrput_mode)
{
	assert(index <= 7 && interrput_mode & 0x0f);
	usart_index[index]->FIFOINTENSET = interrput_mode;
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		获取 USART FIFO 状态
//	@param		index			所选 USART 标识
//	@return		uint32_t		FIFO 状态
//	Sample usage:				status = zf_usart_get_fifo_status( USART_INDEX0 );
//-------------------------------------------------------------------------------------------------------------------
uint32_t zf_usart_get_fifo_status (flexcomm_index_list index)
{
	assert(index <= 7);																			// 确认参数正确
	return usart_index[index]->FIFOSTAT;
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		获取 USART CFG 状态
//	@param		index			所选 USART 标识
//	@return		uint32_t		FIFO CFG 状态
//	Sample usage:				status = zf_usart_get_fifo_config( USART_INDEX0 );
//-------------------------------------------------------------------------------------------------------------------
uint32_t zf_usart_get_fifo_config (flexcomm_index_list index)
{
	assert(index <= 7);																			// 确认参数正确
	return usart_index[index]->FIFOCFG;
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		设置 USART FIFO 状态
//	@param		index			所选 USART 标识
//	@param		mask			清除对应的 FIFO 状态
//	Sample usage:				zf_usart_set_fifo_status(USART_INDEX0, USART_FIFO_STATUS_TXERR);
//	note：						这里就是写 fifostat 的 [0:1] 来清空发送接收报错的
//-------------------------------------------------------------------------------------------------------------------
void zf_usart_set_fifo_status (flexcomm_index_list index, uint32_t mask)
{
	assert(index <= 7);																			// 确认参数正确
	usart_index[index]->FIFOSTAT |= mask & 0x00000003UL;
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		设置 USART CFG 状态
//	@param		index			所选 USART 标识
//	@param		mask			清除对应的 FIFO 设置
//	Sample usage:				zf_usart_set_fifo_config(USART_INDEX0, USART_FIFO_CFG_WAKETX);
//	note：						这里就是写 fifocfg 的 [15:14] 来清空发送接收 fifo 的
//-------------------------------------------------------------------------------------------------------------------
void zf_usart_set_fifo_config (flexcomm_index_list index, uint32_t mask)
{
	assert(index <= 7);																			// 确认参数正确
	usart_index[index]->FIFOCFG |= mask & 0x00030000UL;
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		获取 USART FIFO TX 剩余发送字节
//	@param		index			所选 USART 标识
//	@return		uint8_t			发送缓冲内数据个数
//	Sample usage:				datalen = zf_usart_get_fifo_TXLVL(USART_INDEX0);
//-------------------------------------------------------------------------------------------------------------------
uint8_t zf_usart_get_fifo_TXLVL (flexcomm_index_list index)
{
	assert(index <= 7);																			// 确认参数正确
	return (uint8_t)(( usart_index[index]->FIFOSTAT & 0x00001F00 ) >> 8);
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		获取 USART FIFO RX 缓存数据个数
//	@param		index			所选 USART 标识
//	@return		uint8_t			接收缓冲内数据个数
//	Sample usage:				datalen = zf_usart_get_fifo_RXLVL(USART_INDEX0);
//-------------------------------------------------------------------------------------------------------------------
uint8_t zf_usart_get_fifo_RXLVL (flexcomm_index_list index)
{
	assert(index <= 7);																			// 确认参数正确
	return (uint8_t)((usart_index[index]->FIFOSTAT & 0x001F0000) >> 16);
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		USART 写一个字节
//	@param		index			所选 USART 标识
//	@param		data			数据
//	Sample usage:				zf_usart_write_byte( USART_INDEX0, 0xA5 );
//-------------------------------------------------------------------------------------------------------------------
void zf_usart_write_byte (flexcomm_index_list index, uint8_t data)
{
	assert(index <= 7);
	while(zf_usart_get_fifo_TXLVL(index) != 0){}
	usart_index[index]->FIFOWR = data;
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		USART 读一个字节
//	@param		index			所选 USART 标识
//	@return		uint8_t			数据
//	Sample usage:				data = zf_usart_read_byte(USART_INDEX0);
//-------------------------------------------------------------------------------------------------------------------
uint8_t zf_usart_read_byte (flexcomm_index_list index)
{
	assert(index <= 7);
	if(zf_usart_get_fifo_RXLVL(index) > 0)
		return (uint8_t)usart_index[index]->FIFORD;
	else
		return 0x00;
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		USART 写数据块
//	@param		index			所选 USART 标识
//	@param		data			数据对应地址
//	@param		length			数据长度
//	@return		size_t			未读发送的数据长度
//	Sample usage:				zf_usart_write_blocking( USART_INDEX0, txbuff, sizeof(txbuff) - 1);
//-------------------------------------------------------------------------------------------------------------------
size_t zf_usart_write_blocking (flexcomm_index_list index, uint8_t *data, size_t length)
{
	uint8_t over_time = 0;
	assert(index <= 7 && data != NULL && length != 0);											// 确认参数正确

	if (0U == (usart_index[index]->FIFOCFG & USART_FIFOCFG_ENABLETX_MASK))						// 未开启发送使能
	{
		return length;																			// 返回整个发送长度
	}
	for (; length > 0U; length--)
	{
		while (0U == (usart_index[index]->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK))			// 等待发送空闲
		{
			over_time ++;																		// 超时自增
			delay_us(5);																		// 115200 下发送一个字节大概要 86us 左右 这里 5us 检查一次
			if(over_time > 200)																	// 超时 1ms
				return length;																	// 返回剩余发送长度
		}
		usart_index[index]->FIFOWR = *data;
		data++;
		over_time = 0;
	}
	/* Wait to finish transfer */
	while (0U == (usart_index[index]->STAT & USART_STAT_TXIDLE_MASK))
	{
		over_time ++;
		delay_us(5);																			// 115200 下发送一个字节大概要 86us 左右 这里 5us 检查一次
		if(over_time > 200)
			return (length + 1);
	}
	return 0;
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		USART 读数据块
//	@param		index			所选 USART 标识
//	@param		data			缓存对应地址
//	@param		length			数据长度
//	@return		size_t			未读取到的数据长度
//	Sample usage:				zf_usart_read_blocking( USART_INDEX0, txbuff, sizeof(txbuff) - 1);
//-------------------------------------------------------------------------------------------------------------------
size_t zf_usart_read_blocking (flexcomm_index_list index, uint8_t *data, size_t length)
{
	uint8_t over_time = 0;
	assert(index <= 7 && data != NULL && length != 0); 											// 确认参数正确

	uint32_t statusFlag;
	status_t status = kStatus_Success;

	if ((usart_index[index]->FIFOCFG & USART_FIFOCFG_ENABLERX_MASK) == 0U)						// 未开启接收使能
	{
		return length;																			// 返回整个读取长度
	}
	for (; length > 0U; length--)
	{
		while ((usart_index[index]->FIFOSTAT & USART_FIFOSTAT_RXNOTEMPTY_MASK) == 0U)			// 等待下个数据
		{
		
			over_time ++;																		// 超时自增
			delay_us(5);																		// 115200 下发送一个字节大概要 86us 左右 这里 5us 检查一次
			if(over_time > 200)																	// 超时 1ms
			{
				if ((usart_index[index]->FIFOSTAT & USART_FIFOSTAT_RXERR_MASK) != 0U)			// 发送失败
				{
					usart_index[index]->FIFOCFG |= USART_FIFOCFG_EMPTYRX_MASK;					// 清空发送 FIFO
					usart_index[index]->FIFOSTAT |= USART_FIFOSTAT_RXERR_MASK;					// 清除发送错误
				}
				return length;																	// 返回剩余发送长度
			}
		}
		statusFlag = usart_index[index]->STAT;
		usart_index[index]->STAT |= statusFlag;
		if ((statusFlag & USART_STAT_PARITYERRINT_MASK) != 0U)
		{
			status = kStatus_USART_ParityError;
		}
		if ((statusFlag & USART_STAT_FRAMERRINT_MASK) != 0U)
		{
			status = kStatus_USART_FramingError;
		}
		if ((statusFlag & USART_STAT_RXNOISEINT_MASK) != 0U)
		{
			status = kStatus_USART_NoiseError;
		}

		if (kStatus_Success == status)
		{
			*data = (uint8_t)usart_index[index]->FIFORD;										// 发送数据
			data++;																				// 数据指针自增
		}
		else
		{
			return length;																		// 返回剩余发送长度
		}
	}
	return 0;
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		USART 传输方式写数据块
//	@param		index			所选 USART 标识
//	@param		data			数据对应地址
//	@param		length			数据长度
//	Sample usage:				zf_usart_transfer_write( DEMO_USART, g_txBuffer, sizeof(g_txBuffer) );
//-------------------------------------------------------------------------------------------------------------------
void zf_usart_transfer_write (flexcomm_index_list index, uint8_t *data, size_t length)
{
	usart_transfer_t transfer_t;
	assert(index <= 7 && data != NULL && length != 0);											// 确认参数正确

	transfer_t.data			= data;
	transfer_t.dataSize		= length;
	USART_TransferSendNonBlocking(usart_index[index], &g_uartHandle[index], &transfer_t);
}

//-------------------------------------------------------------------------------------------------------------------
//	@brief		USART 传输方式读数据块
//	@param		index			所选 USART 标识
//	@param		data			缓存对应地址
//	@param		length			数据长度
//	Sample usage:				zf_usart_transfer_read( DEMO_USART, g_rxBuffer, sizeof(g_rxBuffer) );
//-------------------------------------------------------------------------------------------------------------------
void zf_usart_transfer_read (flexcomm_index_list index, uint8_t *data, size_t length)
{
	usart_transfer_t transfer_t;
	assert(index <= 7 && data != NULL && length != 0); 											// 确认参数正确

	transfer_t.data			= data;
	transfer_t.dataSize		= length;
	USART_TransferReceiveNonBlocking(usart_index[index], &g_uartHandle[index], &transfer_t, NULL);
}
